"""
    创建代理池
    代理ip服务商官网：https://www.zdaye.com/；文档：https://www.zdaye.com/doc/api/ShortProxy/
"""
import json
import time
import traceback
from typing import List

import redis
import requests

from conf.config import REDIS_CONFIG, config, logger


class ProxyPool(object):
    """
    代理池对象
    """
    pool = redis.ConnectionPool(
        host=REDIS_CONFIG["host"], port=REDIS_CONFIG["port"],
        db=REDIS_CONFIG["db"], password=REDIS_CONFIG["password"],
        decode_responses=True
    )
    url = "http://www.zdopen.com/ShortProxy/GetIP/"
    api = config["zdaye"]["api"]
    akey = config["zdaye"]["akey"]
    count = config["zdaye"]["count"]
    timespan = config["zdaye"]["timespan"]

    def __init__(self, *args, **kwargs):
        super(ProxyPool, self).__init__(*args, **kwargs)

    def get_proxy_list(self) -> List[str]:
        """
        从代理商服务器获取代理ip
        :return:
        """
        params = {
            "api": self.api, "akey": self.akey,
            "count": self.count, "timespan": self.timespan, "type": 3
        }

        try:
            resp = requests.get(url=self.url, params=params)
        except requests.RequestException:
            error_str = traceback.format_exc()
            logger.error(error_str)
            return []

        resp = json.loads(resp.content.decode())
        if resp['code'] != "10001":
            logger.error(f"代理ip获取失败，详情：{resp}")
            return []

        proxy_list = list()
        for proxy in resp['data']['proxy_list']:
            proxy_list.append(f"{proxy['ip']}:{proxy['port']}")

        return proxy_list

    def add_proxy_ip(self, proxy_list: List[str]):
        """
        添加代理ip到池子里
        :param proxy_list: 代理ip列表
        :return:
        """
        redis_conn = redis.Redis(connection_pool=self.pool)

        proxy_pool_name = config["proxy_pool_name"]
        try:
            for proxy in proxy_list:
                proxy_list_latest = redis_conn.lrange(proxy_pool_name, 0, -1)

                if proxy in proxy_list_latest:  # 去重。redis不使用set类型的原因，是因为列表类型才能满足先进先出的策略
                    continue

                if len(proxy_list_latest) >= config["proxy_pool_length_limit"]:  # 内存溢出防线
                    redis_conn.lpop(config["proxy_pool_name"])

                redis_conn.rpush(config["proxy_pool_name"], proxy)
        finally:
            if "redis_conn" in dir():
                redis_conn.close()

    def delete_proxy_ip(self):
        # TODO 2023-5-28 通过ping命令来删除无效的ip，这样池子的长度可以设置得更大些
        pass

    def run(self):
        while True:
            proxy_list = self.get_proxy_list()
            self.add_proxy_ip(proxy_list)

            time.sleep(config["zdaye"]["time_interval_for_get_ip"])


def main():
    proxy_pool = ProxyPool()

    start_time = time.time()
    timeout = 60 * 5  # 超时时间（秒）

    while (time.time() - start_time) < timeout:
        proxy_list = proxy_pool.get_proxy_list()
        logger.info(f"{proxy_list}")
        proxy_pool.add_proxy_ip(proxy_list)

        time.sleep(config["zdaye"]["time_interval_for_get_ip"])


if __name__ == '__main__':
    main()
